import * as lodash from "lodash";
import * as Koa from 'koa';
import { addUser, delUser, updateUser, searchUser, searchUserTotalNumbers } from "../entity/user";
import { encrypt, joinDefaultFields, validatePhone } from "../utils/index";
import { wxGet } from "../utils/axiosHttp";
import dayjs = require("dayjs");
import { addUserTemp, searchUserTemp, updateUserTemp } from "../entity/user-temp";
import { getCode, storeCode } from "../database/redisUtils";
const jwt = require('jsonwebtoken');
import { JWT_SECRET } from "../constants";
import { sendSms } from "../utils/sendSms";
// TODO：commonjs 模式下引用 esmodule 模块
let nanoid: any = null;
(async () => {
  nanoid = (await eval("import('nanoid')")).nanoid;
})();

const errorMsg = `服务器错误：${'user'}`;
const successMsg = `成功：${'user'}`;

export default class UserService {
  /**
   * 添加用户
   * @param ctx 
   */
  addUser = async (ctx: Koa.Context) => {
    try {
      const userInfo = ctx.request.body;
      const _userInfo = joinDefaultFields(userInfo, "userFields");
      _userInfo.uid = nanoid(18);
      _userInfo.create_time = dayjs().format("YYYY-MM-DD HH:mm:ss");
      _userInfo.pic_url = nanoid(8);
      
      const result: any = _userInfo && await addUser(ctx, _userInfo);
      if (!result) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else if (!result.success) {
        ctx.fail(null, result.msg ||errorMsg, -1);
      } else {
        ctx.success(null, successMsg);
      }
    } catch (error) {
      ctx.fail(null, errorMsg, -1);
    }
  };

    /**
   * 删除用户
   * @param ctx 
   */
  delUser = async (ctx: Koa.Context) => {
    try {
      const { uid } = ctx.request.body;
      if (!uid || !uid.length) return ctx.fail(null, "uid不能为空", -1);
      const uids = Array.isArray(uid)? uid : [uid];
      let condition = `uid IN (${uids.map((i) => `"${i}"`).join(",")})`;
      const result: any =  !!uids.length && await delUser(ctx, { condition });
      if (!result) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else if (!result.success) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        ctx.success(null, successMsg);
      }
    } catch (error) {
      ctx.fail(null, errorMsg, -1);
    }
  };

    /**
   * 修改用户
   * @param ctx 
   */
  updateUser = async (ctx: Koa.Context) => {
    try {
      const userInfo = ctx.request.body;
      userInfo.update_time = dayjs().format("YYYY-MM-DD HH:mm:ss"); // 最后的更新时间
      const result: any = userInfo && await updateUser(ctx, userInfo);
      if (!result) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else if (!result.success) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        ctx.success(null, successMsg);
      }
    } catch (error) {
      ctx.fail(null, errorMsg, -1);
    }
  };

    /**
   * 查询用户
   * orders 排序格式 { column: "id", order: "desc"/"asc" }
   * @param ctx 
   */
  searchUser = async (ctx: Koa.Context) => {
    try {
      const params = ctx.request.body;
      const { uid, name, orders, pageNumber, pageSize } = params || {}; // 查询条件
      if (!pageNumber || !pageSize) return ctx.fail(null, "pageNumber、pageSize不能为空", -1);
      // 相等的条件
      let condition = "";
      let equals: string | string[] = [];
      uid && (equals.push(` uid = "${uid}"`));
      name && (equals.push(` name = "${name}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      // 排序的条件
      orders?.column && orders.order && (condition += ` ORDER BY ${orders.column} ${orders.order}`);
      // 分页的条件
      condition += ` LIMIT ${pageSize} OFFSET ${(pageNumber - 1) * pageSize}`;
      const result: any = await searchUser(ctx, { condition });
      const resultNums: any = await searchUserTotalNumbers(ctx);
      if (!result) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else if (!result.success) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        ctx.success({
          list: result.data || [],
          total: resultNums?.data || 0,
          pageNumber: pageNumber,
          pageSize: pageSize,
        }, successMsg);
      }
    } catch (error) {
      ctx.fail(null, errorMsg, -1);
    }
  };
  
  /**
   * web端 - 获取用户信息
   * @param ctx 
   */
  webUserInfo = async (ctx: Koa.Context) => {
    try {
      ctx.success({}, "成功");
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };

  /**
   * web端-用户登录
   * @param ctx
   * @returns 返回 token 和 用户信息
   */
  webUserLogin = async (ctx: Koa.Context) => {
    try {
      const params = ctx.request.body;
      const { account, password } = params || {}; // 查询条件
      // 相等的条件
      let condition = "";
      let equals: string | string[] = [];
      account && (equals.push(` account = "${account}"`));
      password && (equals.push(` password = "${password}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      const result = await searchUser(ctx, { condition });
      if (!result?.success || !result.data?.length || result.data.length > 1) {
        ctx.fail(null, "登录失败，账号或密码错误", -1);
      } else {
        const token = jwt.sign({
          account,
        }, JWT_SECRET, {
          expiresIn: '5h'
        });
        const userInfo = result.data[0];
        delete userInfo.password;
        ctx.success({ token, userInfo }, "登录成功");
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
  

  /**
   * 生成验证码校验
   * @param ctx 
   */
  webUserSendCode = async (ctx: Koa.Context) => {
    try {
      let { phone, pexpire } = ctx.request.body || {};
      if (!validatePhone(phone)) {
        return ctx.fail(null, "手机号格式不正确", -1);
      }
      const code =  Math.floor(100000 + Math.random() * 900000).toString();
      // 生产环境开启短信发送
      if (process.env['ALIBABA_CLOUD_ENABLE'] === "1") {
        const sendSmsRes: any = await sendSms({
          phoneNumbers: phone,
          signName: "当下景",
          templateCode: "SMS_471125065",
          templateParam: { code }
        });
        if (typeof(sendSmsRes) === "string" || sendSmsRes.status !== "success") {
          return ctx.fail(null, "验证码发送失败", -1);
        }
        pexpire += 60 * 1000;
        await storeCode(phone, code, pexpire);
        ctx.success(null, "验证码已发送");
      } else {
        pexpire += 60 * 1000;
        await storeCode(phone, code, pexpire);
        ctx.success("开发环境生成的验证码：" + code, "成功");
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
  
  /**
   * 用户注册
   * @param ctx 
   */
  webUserRegister = async (ctx: Koa.Context) => {
    try {
      const { name, account, code, password } = ctx.request.body || {};
      if (!validatePhone(account)) {
        return ctx.fail(null, "手机号格式不正确", -1);
      }
      // 相等的条件
      let condition = "";
      let equals: string | string[] = [];
      account && (equals.push(` account = "${account}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      const targetUserRes = await searchUser(ctx, { condition });
      if (targetUserRes.success && targetUserRes.data.length) {
        return ctx.fail(null, "该手机号已被注册", -1);
      }
      // 校验验证码
      const resCode = await getCode(account);
      if (!resCode) {
        return ctx.fail(null, "验证码已过期，请重新发送", -1);
      } else if (resCode !== code) {
        return ctx.fail(null, "验证码错误", -1);
      }
      // 保存用户信息
      const _userInfo = joinDefaultFields({
        name,
        account,
        password,
      }, "userFields");
      _userInfo.uid = nanoid(18);
      _userInfo.create_time = dayjs().format("YYYY-MM-DD HH:mm:ss");
      _userInfo.pic_url = nanoid(8);
      const result: any = _userInfo && await addUser(ctx, _userInfo);
      if (!result) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else if (!result.success) {
        ctx.fail(null, result.msg ||errorMsg, -1);
      } else {
        ctx.success(null, successMsg);
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
  
  appletGetToken = async (ctx: Koa.Context) => {
    try {
      const { code } = ctx.request.body;
      if (!code) return ctx.fail(null, "参数code不存在", -1);
      const res = await wxGet({ js_code: code });
      // const result = {
      //   userInfo: users,
      //   token: JWT.sign({ id: uId }, JWT_SECRET, { expiresIn: 24 * 60 * 60 })
      // };
      // 【先简单的进行拼接】
      const info = {
        utid: nanoid(18),
        create_time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
        token: encrypt(res.openid + "-" + res.session_key),
      };
      const result = await addUserTemp(ctx, Object.assign({ permission: "visitor" }, info));
      if (!result.success) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        ctx.success(info, successMsg);
      }
    } catch (error) {
      ctx.fail(error, -1);
    }
  };

  appeltUserCheckToken = async (ctx: Koa.Context) => {
    try {
      const { token } = ctx.query;
      if (!token) return ctx.fail(null, "参数token不存在", -1);
      // 相等、模糊条件
      let condition = "";
      let equals: string | string[] = [];
      token && (equals.push(` token = "${token}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      const result = await searchUserTemp(ctx, { condition });
      if (!result.success || !result.data?.length) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        ctx.success({
          isLogined: !!result.data?.length
        }, successMsg);
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
  
  /**
   * 获取用户详细信息
   * @param ctx 
   */
  appletGetUserInfo = async (ctx: Koa.Context) => {
    try {
      const { token } = ctx.request.body;
      if (!token) return ctx.success(null, successMsg);
      // 相等、模糊条件
      let condition = "";
      let equals: string | string[] = [];
      token && (equals.push(` token = "${token}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      const result = await searchUserTemp(ctx, { condition });
      if (!result.success || result.data?.length != 1) {
        ctx.fail(null, result.msg || errorMsg, -1);
      } else {
        // 相等的条件
        if (!result.data[0]?.uid) return ctx.success(null, successMsg);
        let _condition = "";
        let equals: string | string[] = [];
        result.data[0]?.uid && (equals.push(` uid = "${result.data[0].uid}"`));
        equals = equals.join(" AND");
        equals && (_condition += `WHERE ${equals}`);
        const suRes = await searchUser(ctx, { condition: _condition });
        if (suRes.success) {
          ctx.success(suRes.data, successMsg);
        } else {
          ctx.fail(null, suRes.msg || errorMsg, -1);
        }
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
  
  /**
   * 用户账号登录
   * @param ctx 
   */
  appletUserLogin = async (ctx: Koa.Context) => {
    try {
      const params = ctx.request.body;
      const { account, password, token, utid } = params || {}; // 查询条件
      // 相等的条件
      let condition = "";
      let equals: string | string[] = [];
      account && (equals.push(` account = "${account}"`));
      password && (equals.push(` password = "${password}"`));
      equals = equals.join(" AND");
      equals && (condition += `WHERE ${equals}`);
      const result = await searchUser(ctx, { condition });
      if (!result?.success || !result.data?.length || result.data.length > 1) {
        ctx.fail(null, "登录失败，账号或密码错误", -1);
      } else {
        const updateTempUser = {
          utid,
          token,
          permission: "customer",
          uid: result.data[0].uid,
          update_time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
        };
        const utRes = await updateUserTemp(ctx, updateTempUser);
        if (utRes.success) {
          ctx.success(null, successMsg);
        } else {
          ctx.fail(null, utRes.msg || errorMsg, -1);
        }
      }
    } catch (error) {
      ctx.fail(null, error, -1);
    }
  };
}
